package db

import (
	"core/graylog"
	"core/mysql"
	"core/rds"
	"core/utils"
	"encoding/json"
	"fmt"
	"time"

	"github.com/go-redis/redis"
)

type Player struct {
	Id   int64  `xorm:"pk"`
	Data string `xorm:"TEXT"`
}

// openId对应表， 根据openId查询uid
type OpenIdData struct {
	OpenId string `xorm:"varchar(64) notnull unique"` //
	UID    int64  `xorm:"int(11) notnull uid index"`  //
}

func MakeAofKey(t time.Time) string {
	return fmt.Sprintf("user:aof:%d", t.Weekday())
}

func RunAof(aofKey string) {
	var err error
	defer utils.CatchPanicAndErr("RunAof", &err, graylog.M{"aofKey": aofKey})
	for {
		uidStr, err := rds.GetDefaultClient().SPop(aofKey).Result()
		if err != nil {
			if err == redis.Nil {
				err = nil
			} else {
				utils.Error(err)
			}
			return
		}
		SaveMysqlFromRedis(utils.ToInt64(uidStr))
		time.Sleep(time.Millisecond * 20)
	}
}

func SaveMysqlFromRedis(uid int64) (err error) {
	defer utils.CatchPanicAndErr("SaveMysqlFromRedis", &err, graylog.M{"playerId": uid})
	defer func() {
		if err == mysql.NotFound {
			graylog.Info("异常", graylog.M{
				"uid":     uid,
				"errInfo": "落地失败，用户未找到",
			})
		} else if err != nil {
			AddActiveUser(uid)
		}
	}()

	u, err := LoadByUID(uid, false)
	if err != nil {
		return
	}
	userByte, err := json.Marshal(u)
	if err != nil {
		return
	}
	p := &Player{
		Id:   uid,
		Data: string(userByte),
	}
	exist, err := mysql.X.Exist(&Player{Id: uid})
	if err != nil {
		return
	}
	if exist {
		_, err = mysql.X.ID(uid).Update(p)
		if err != nil {
			utils.Error(err)
			return
		}
	} else {
		err = mysql.Create(p)
		if err != nil {
			utils.Error(err)
			return
		}
	}

	go graylog.Info("落地用户数据", graylog.M{
		"uid":    uid,
		"name":   u.Name,
		"grass":  u.Grass,
		"levels": fmt.Sprintf("%+v", u.Level),
	})
	return
}

func LoadFromMysql(uid int64) (u *User, err error) {
	p := &Player{Id: uid}
	err = mysql.Load(p)
	if err != nil {
		return
	}
	u = new(User)
	err = json.Unmarshal([]byte(p.Data), u)
	if err != nil {
		return
	}
	return
}

func SaveToRedis(u *User) (err error) {
	levelSets := make(map[string]interface{})
	for menuId, v := range u.Level {
		for level, detail := range v {
			levelSets[fmt.Sprintf("%d:%d", menuId, level)] = encodeLevelDetail(&detail)
		}
	}
	if len(levelSets) == 0 {
		levelSets["1:1"] = encodeLevelDetail(&LevelDetail{Unlock: true, FinishNum: 0})
	}
	userKey := MakeUserKey(u.UID)
	userLevelKey := MakeUserLevelKey(u.UID)
	userClient := rds.GetCacheClient(u.UID)
	err = userClient.HMSet(userLevelKey, levelSets).Err()
	if err != nil {
		return
	}
	err = userClient.Expire(userLevelKey, userExpire).Err()
	if err != nil {
		return
	}
	err = u.Save(FieldsAll...)
	if err != nil {
		return
	}
	err = userClient.Expire(userKey, userExpire).Err()
	if err != nil {
		return
	}
	return
}

func AddActiveUser(uid int64) (err error) {
	defer utils.CatchPanicAndErr("AddActiveUser", &err, graylog.M{"uid": uid})
	err = rds.GetDefaultClient().SAdd(MakeAofKey(time.Now()), uid).Err()
	return
}

// 查询uid，根据openId（登录）
func LoadUIDByOpenId(openId string) (uid int64, err error) {
	data := &OpenIdData{OpenId: openId}
	err = mysql.Load(data)
	if err != nil {
		utils.Error(err)
		return
	}
	uid = data.UID
	return
}

// 查询openId
func LoadOpenIdByUID(uid int64) (openId string, err error) {
	data := &OpenIdData{UID: uid}
	err = mysql.Load(data)
	if err != nil {
		utils.Error(err)
		return
	}
	openId = data.OpenId
	return
}

// 创建openId-uid对应数据（注册）
func CreateOpenIdData(openId string, uid int64) (err error) {
	exist, err := mysql.X.Exist(&OpenIdData{OpenId: openId})
	if err != nil {
		return
	}
	utils.Info(openId, exist)
	if exist {
		sql := "update open_id_data set uid = ? where open_id = ?"
		_, err = mysql.X.Exec(sql, uid, openId)
	} else {
		data := &OpenIdData{OpenId: openId, UID: uid}
		err = mysql.Create(data)
	}

	if err != nil {
		utils.Error(err)
		return
	}
	return
}

// 删除openId（删号）
func DelOpenIdData(openId string) (err error) {
	data := &OpenIdData{OpenId: openId}
	err = mysql.Del(data)
	if err != nil {
		utils.Error(err)
		return
	}
	return
}
